﻿using System;
using System.Linq;

namespace SG.Sys.Console.CommandProcessing
{
    public delegate Command CommandParser(string raw);

    public class Command : IEquatable<Command>
    {
        public Command(string raw, string cmd, string[] args, char? argsJoiner = ' ', char? cmdArgsSeperator = ' ', char? argsLeft = null, char? argsRight = null)
        {
            Raw = raw;
            Executable = cmd;
            Arguments = args;

            ArgsJoiner = argsJoiner;
            CmdArgsSeperator = cmdArgsSeperator;
            ArgsLeft = argsLeft;
            ArgsRight = argsRight;
        }

        public string Raw { get; private set; }
        public string Executable { get; private set; }
        public string[] Arguments { get; private set; }

        public char? ArgsJoiner { get; private set; }
        public char? CmdArgsSeperator { get; private set; }
        public char? ArgsLeft { get; private set; }
        public char? ArgsRight { get; private set; }

        private string _normalizedCache;

        public string Normalized
        {
            get { return _normalizedCache ?? (_normalizedCache = Executable + CharOrEmpty(CmdArgsSeperator) + CharOrEmpty(ArgsLeft) + ArgumentsJoined + CharOrEmpty(ArgsRight)); }
        }

        public string ArgumentsJoined
        {
            get
            {
                if (Arguments == null || Arguments.Length == 0)
                    return string.Empty;

                return Arguments.Aggregate(string.Empty,
                                           (seq, arg) => (string.IsNullOrEmpty(seq) ? string.Empty : seq + CharOrEmpty(ArgsJoiner)) + arg);
            }
        }

        public bool IsEmpty
        {
            get { return string.IsNullOrWhiteSpace(Raw); }
        }

        public static string CharOrEmpty(char? @this)
        {
            return @this != null ? @this.ToString() : string.Empty;
        }

        public override string ToString()
        {
            return Normalized;
        }

        public override int GetHashCode()
        {
            return Normalized.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is Command)
                return Equals((Command) obj);

            return false;
        }

        public bool Equals(Command other)
        {
            return Normalized == other.Normalized;
        }
    }
}
